#include "CVMDataTypes.h"
#include "CCoreException.h"
#include "data/CFunction.h"

char* copy(char* data)
{
    int sz;
    switch ((CVMDataTypes)data[0])
    {
        case CVMDataTypes::NULL_:
        {
            sz = 1;
            break;
        };
        case CVMDataTypes::FALSE:
        {
            sz = 1;
            break;
        };
        case CVMDataTypes::TRUE:
        {
            sz = 1;
            break;
        };
        case CVMDataTypes::NUMBER:
        {
            sz = sizeof(double) + 1;
            break;
        };
        case CVMDataTypes::FUNCTION:
        {
            sz = sizeof(CFunction) + 1;
            break;
        };
        default: throw CCoreException(CCoreException::VM_EXCEPTION_WRONG_OPERAND, "<VMDataType.copyOperand>");

    }
    char* rslt = new char[sz];
    memcpy(rslt, data, sz);
    return rslt;
}

bool isTrue(char* data)
{
    switch((CVMDataTypes)data[0])
    {
        case CVMDataTypes::NULL_:
        case CVMDataTypes::FALSE:
        {
            return false;
            break;
        }
        case CVMDataTypes::TRUE:
        case CVMDataTypes::NUMBER:
        case CVMDataTypes::FUNCTION:
        {
            return true;
            break;
        }
        default:
            throw CCoreException(CCoreException::VM_EXCEPTION_WRONG_OPERAND, "<operations.boolean.egNeqGteGtLteLt>");
    }
}

int sizeof_(char* data)
{
    switch((CVMDataTypes)data[0])
    {
        case CVMDataTypes::NULL_:
        case CVMDataTypes::FALSE:
        case CVMDataTypes::TRUE:
        {
            return sizeof(char);
            break;
        }
        case CVMDataTypes::NUMBER:
        {
            return sizeof(double);
            break;
        }
        default:
            throw CCoreException(CCoreException::VM_EXCEPTION_WRONG_OPERAND, "<operations.boolean.egNeqGteGtLteLt>");
    }
}

double getNumber(char* data)
{
    return *(double*)(data+1);
}

void setNumber(double number, char* data)
{
    *(double*)(data + 1) = number;
}

int compare(char* data1, char* data2)
{
    int sz1 = sizeof_(data1);
    int sz2 = sizeof_(data2);

    if (sz1 != sz2) throw CCoreException(CCoreException::VM_EXCEPTION_WRONG_OPERAND, "<CVMDataTypess.compare>");

    if (sz1 == sizeof(char)) return memcmp(data1, data2, sz1);

    if ((CVMDataTypes)data1[0] == CVMDataTypes::NUMBER && (CVMDataTypes)data2[0] == CVMDataTypes::NUMBER)
    {
        double nmbr1 = getNumber(data1);
        double nmbr2 = getNumber(data2);
        if (nmbr1 == nmbr2) return 0;
        if (nmbr1 > nmbr2) return 1;
        return -1;
    }

    throw CCoreException(CCoreException::VM_EXCEPTION_WRONG_OPERAND, "<CVMDataTypess.compare>");
}
